package carAgents;

import jade.core.Agent;
import jade.core.AID;
import jade.core.behaviours.*;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;

public class RequestAgent extends Agent {
  private RequestAgentGui myGui;
  private String targetStartP;
  //list of know offerers
  private AID[] offeringAgents;
  
	protected void setup() {
	  targetStartP = "";
	  System.out.println("Welcome! Asking agent "+getAID().getLocalName()+" is waiting for an offer.");
	  myGui = new RequestAgentGui (this);
	  myGui.display();
		//time interval for asking agent between sending cfp
		//input argment from command line
		int interval = 20000;
		Object[] args = getArguments();
		if (args != null && args.length > 0) interval = Integer.parseInt(args[0].toString());
	  addBehaviour(new TickerBehaviour(this, interval)
	  {
		  protected void onTick()
		  {
			  //look for only if there is a starting point call
			  if (!targetStartP.equals(""))
			  {
				  System.out.println("I am looking for statring point " + targetStartP);
				  //update a list of known offers
				  DFAgentDescription template = new DFAgentDescription();
				  ServiceDescription sd = new ServiceDescription();
				  sd.setType("car-offer");
				  template.addServices(sd);
				  try
				  {
					  DFAgentDescription[] result = DFService.search(myAgent, template);
					  System.out.println("Offer found:");
					  offeringAgents = new AID[result.length];
					  for (int i = 0; i < result.length; ++i)
					  {
						  offeringAgents[i] = result[i].getName();
						  System.out.println(offeringAgents[i].getLocalName());
					  }
				  }
				  catch (FIPAException fe)
				  {
					  fe.printStackTrace();
				  }

				  myAgent.addBehaviour(new RequestPerformer());
			  }
		  }
	  });
  }

	//method call by gui for reqest
	public void lookForJourney(final String startP)
	{
		addBehaviour(new OneShotBehaviour()
		{
			public void action()
			{
				targetStartP = startP;
				System.out.println("The starting point is " + targetStartP);
			}
		});
	}

    protected void takeDown() {
		myGui.dispose();
		System.out.println("Requesting agent " + getAID().getName() + " is dead.");
	}
  //TODO: trzeba przerobić całą to funkcję tu się kryje magiczne wyszukiwanie a taże chuje muje i dzikie węże
   
	private class RequestPerformer extends Behaviour {
	  private AID bestOffer;
	  private int bestPrice;
	  private int repliesCnt = 0;
	  private MessageTemplate mt;
	  private int step = 0;
	
	  public void action() {
	    switch (step) {
	    case 0:
	      //call for proposal (cfp) do znalezionych sprzedajacych
	      ACLMessage cfp = new ACLMessage(ACLMessage.CFP);
	      for (int i = 0; i < offeringAgents.length; ++i) {
	        cfp.addReceiver(offeringAgents[i]);
	      } 
	      cfp.setContent(targetStartP);
	      cfp.setConversationId("book-trade");
	      cfp.setReplyWith("cfp"+System.currentTimeMillis()); //unikalna wartosc
	      myAgent.send(cfp);
	      mt = MessageTemplate.and(MessageTemplate.MatchConversationId("book-trade"),
	                               MessageTemplate.MatchInReplyTo(cfp.getReplyWith()));
	      step = 1;
	      break;
	    case 1:
	      //odbior ofert od sprzedajacych
	      ACLMessage reply = myAgent.receive(mt);
	      if (reply != null) {
	        if (reply.getPerformative() == ACLMessage.PROPOSE) {
	          //otrzymano oferte
	          int price = Integer.parseInt(reply.getContent());
	          if (bestOffer == null || price < bestPrice) {
	            //jak na razie to najlepsza oferta
	            bestPrice = price;
	            bestOffer = reply.getSender();
	          }
	        }
	        repliesCnt++;
	        if (repliesCnt >= offeringAgents.length) {
	          //otrzymano wszystkie oferty -> nastepny krok
	          step = 2; 
	        }
	      }
	      else {
	        block();
	      }
	      break;
	    case 2:
	      //zakup najlepszej oferty
	      ACLMessage order = new ACLMessage(ACLMessage.ACCEPT_PROPOSAL);
          order.addReceiver(bestOffer);
	      order.setContent(targetStartP);
	      order.setConversationId("book-trade");
	      order.setReplyWith("order"+System.currentTimeMillis());
	      myAgent.send(order);
	      mt = MessageTemplate.and(MessageTemplate.MatchConversationId("book-trade"),
	                               MessageTemplate.MatchInReplyTo(order.getReplyWith()));
	      step = 3;
	      break;
	    case 3:      
	      //potwierdzenie zakupu przez agenta sprzedajacego
	      reply = myAgent.receive(mt);
	      if (reply != null) {
	        if (reply.getPerformative() == ACLMessage.INFORM) {
	          //zakup zakonczony powodzeniem
	          System.out.println(targetStartP+" kupiona za "+bestPrice+" od "+reply.getSender().getLocalName());
			  System.out.println("Czekam na nowa dyspozycje kupna.");
			  targetStartP = "";
	          //myAgent.doDelete();
	        }
	        else {
	          System.out.println("Zakup nieudany. "+targetStartP+" zostala sprzedana w miedzyczasie.");
	        }
	        step = 4;	//konczy cala interakcje, ktorej celem jest kupno
	      }
	      else {
	        block();
	      }
	      break;
	    }        
	  }
	
	  public boolean done() {
	  	if (step == 2 && bestOffer == null) {
	  		System.out.println(targetStartP+" nie ma w sprzedazy");
	  	}
	    //koniec jesli ksiazki nie ma w sprzedazy lub nie udalo sie kupic
	    return ((step == 2 && bestOffer == null) || step == 4);
	  }
	}

}
